using System.ComponentModel.Design;
using System.IO;
using EnvDTE;
using Microsoft.Practices.RecipeFramework;
using Microsoft.Practices.RecipeFramework.Library;

namespace PrismFactory.SoftwareFactory.Extensions.Actions.VisualStudio
{
    public class AddItemFromStringToProjectItemsAction : ConfigurableAction
    {
        private ProjectItem createdItem;

        public AddItemFromStringToProjectItemsAction()
        {
            Overwrite = false;
            Open = true;
        }

        public override void Execute()
        {
            var vs = GetService<DTE>(true);
            string tempFilename = Path.GetTempFileName();
            using (var sw = new StreamWriter(tempFilename, false))
            {
                sw.WriteLine(Content);
            }

            ProjectItem existingItem = DteHelper.FindItemByName(TargetCollection, TargetFileName, false);
            if (existingItem != null)
            {
                if (Overwrite)
                {
                    OverwriteFile(vs, existingItem.get_FileNames(1), Content);
                    existingItem.Delete();
                }
            }

            createdItem = DteHelper.FindItemByName(TargetCollection, TargetFileName, false);
            if (createdItem == null)
            {
                createdItem = TargetCollection.AddFromTemplate(tempFilename, TargetFileName);
            }

            CreatedProjectItems = createdItem.ProjectItems;
            if (Open)
            {
                Window window = createdItem.Open("{00000000-0000-0000-0000-000000000000}");
                window.Visible = true;
                window.Activate();
            }
            File.Delete(tempFilename);
        }

        private void OverwriteFile(DTE vs, string fullPath, string content)
        {
            EnsureWriteable(vs, fullPath);
        }

        public override void Undo()
        {
            if (createdItem != null)
            {
                createdItem.Delete();
            }
        }

        [Input(Required = true)]
        public string Content { get; set; }

        [Input]
        public bool Open { get; set; }

        [Input(Required = true)]
        public ProjectItems TargetCollection { get; set; }

        [Input(Required = true)]
        public string TargetFileName { get; set; }

        [Output]
        public ProjectItems CreatedProjectItems { get; set; }

        [Input(Required = false)]
        public bool Overwrite { get; set; }

        private static void EnsureWriteable(DTE vs, string filePath)
        {
            if (File.Exists(filePath))
            {
                if (vs.SourceControl.IsItemUnderSCC(filePath) &&
                    !vs.SourceControl.IsItemCheckedOut(filePath))
                {
                    bool checkout = vs.SourceControl.CheckOutItem(filePath);
                    if (!checkout)
                    {
                        throw new CheckoutException(string.Format("Failed to check out the file {0}.", filePath));
                    }
                }
                else
                {
                    // perform an extra check if the file is read only.
                    if (IsReadOnly(filePath))
                    {
                        ResetReadOnly(filePath);
                    }
                }
            }
        }

        private static bool IsReadOnly(string path)
        {
            return (File.GetAttributes(path) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;
        }

        private static void ResetReadOnly(string path)
        {
            File.SetAttributes(path, File.GetAttributes(path) ^ FileAttributes.ReadOnly);
        }
    }
}